#include "MusicTreeViewManager.h"
#include "MusicListManager.h"
#include "Music/MusicInfo.h"

using namespace System;
using namespace SPlayer;

SPlayer::MusicTreeViewManager::MusicTreeViewManager(MusicListManager^ manager,
                                                    System::Windows::Forms::TreeView ^treeView,
                                                    System::Windows::Forms::ContextMenuStrip^ listContextMenu,
                                                    System::Windows::Forms::ContextMenuStrip^ musicContextMenu)
                                                    : _manager(manager),
                                                    _treeView(treeView),
                                                    _listContextMenu(listContextMenu),
                                                    _musicContextMenu(musicContextMenu)
{
    // treeView action
    _treeView->AfterLabelEdit +=
        gcnew System::Windows::Forms::NodeLabelEditEventHandler(this, &SPlayer::MusicTreeViewManager::on_treeView_AfterLabelEdit);

    // musicListManager
    _manager->eventDispatcher->onListAdded +=
        gcnew System::Action<String ^>(this, &MusicTreeViewManager::onListAdded);
    _manager->eventDispatcher->onListRemoved +=
        gcnew System::Action<String ^>(this, &MusicTreeViewManager::onListRemoved);
    _manager->eventDispatcher->onListRenamed +=
        gcnew System::Action<String ^, String ^>(this, &MusicTreeViewManager::onListRenamed);
    _manager->eventDispatcher->onMusicAdded +=
        gcnew System::Action<String ^, Music::MusicInfo ^>(this, &MusicTreeViewManager::onMusicAdded);
    _manager->eventDispatcher->onMusicRemoved +=
        gcnew System::Action<String ^, Music::MusicInfo ^>(this, &MusicTreeViewManager::onMusicRemoved);
}

System::Windows::Forms::TreeNode ^SPlayer::MusicTreeViewManager::listNode(String ^listName)
{
    for each (Node ^ node in this->_treeView->Nodes)
    {
        if (node->Text == listName)
            return node;
    }
    return nullptr;
}

System::Windows::Forms::TreeNode ^SPlayer::MusicTreeViewManager::musicNode(Node ^listnode, String ^path)
{
    if (listnode == nullptr)
        return nullptr;
    auto res = listnode->Nodes->Find(path, false);
    if (0 == res->Length)
        return nullptr;
    return res[0];
}

System::Windows::Forms::TreeNode ^SPlayer::MusicTreeViewManager::musicNode(Node ^listnode, Music::MusicInfo ^musicInfo)
{
    if (listnode == nullptr)
        return nullptr;
    auto res = listnode->Nodes->Find(musicInfo->path, false);
    if (0 == res->Length)
        return nullptr;
    return res[0];
}

System::Windows::Forms::TreeNode ^SPlayer::MusicTreeViewManager::musicNode(String ^listName, Music::MusicInfo ^musicInfo)
{
    auto listnode = listNode(listName);
    if (nullptr != listnode)
    {
        auto res = listnode->Nodes->Find(musicInfo->path, false);
        if (0 != res->Length)
            return res[0];
    }
    return nullptr;
}

System::Windows::Forms::TreeNode ^SPlayer::MusicTreeViewManager::musicNode(String ^listName, String ^path)
{
    auto listnode = listNode(listName);
    if (nullptr != listnode)
    {
        auto res = listnode->Nodes->Find(path, false);
        if (0 != res->Length)
            return res[0];
    }
    return nullptr;
}

System::Windows::Forms::TreeNode ^SPlayer::MusicTreeViewManager::seekMusicNode(System::String ^path)
{
    for each (System::Windows::Forms::TreeNode ^ listnode in _treeView->Nodes)
    {
        auto node = musicNode(listnode, path);
        if (node)
            return node;
    }
    return nullptr;
}


System::Void SPlayer::MusicTreeViewManager::onListAdded(String ^listName)
{
    auto newListNode = this->_treeView->Nodes->Add(listName);

    newListNode->ContextMenuStrip = this->_listContextMenu;
}

System::Void SPlayer::MusicTreeViewManager::onListRemoved(System::String ^listName)
{
    auto listnode = this->listNode(listName);
    listnode->Remove();

    if (eventDispatcher->onListNodeRemoved)
        eventDispatcher->onListNodeRemoved(listnode);
}


System::Void SPlayer::MusicTreeViewManager::onListRenamed(System::String ^listName, System::String ^newListName)
{
    auto node = this->listNode(listName);
    node->Text = newListName;
}


System::Void SPlayer::MusicTreeViewManager::onMusicAdded(String ^listName, Music::MusicInfo ^musicInfo)
{
    auto listNode = this->listNode(listName);
    auto newMusicNode = listNode->Nodes->Add(musicInfo->path, musicInfo->title);

    newMusicNode->ContextMenuStrip = this->_musicContextMenu;
    newMusicNode->Tag = musicInfo;
}

System::Void SPlayer::MusicTreeViewManager::onMusicRemoved(String ^listName, Music::MusicInfo ^musicInfo)
{
    auto listNode = this->listNode(listName);
    auto musicNode = listNode->Nodes->Find(musicInfo->path, true)[0];
    musicNode->Remove();

    if (eventDispatcher->onMusicNodeRemoved)
        eventDispatcher->onMusicNodeRemoved(musicNode);
}

void SPlayer::MusicTreeViewManager::on_treeView_AfterLabelEdit(System::Object ^sender, System::Windows::Forms::NodeLabelEditEventArgs ^e)
{
    if (e->CancelEdit)
        return;

    if (isListNode(e->Node))
    {
        auto orgListName = e->Node->Text;
        auto newListName = e->Label;
        _manager->renameList(orgListName, newListName);
    }

    e->CancelEdit = true;
}

bool SPlayer::MusicTreeViewManager::isListNode(Node ^node)
{
    return node->TreeView == this->_treeView && node->Parent == nullptr;
}

bool SPlayer::MusicTreeViewManager::isMusicNode(Node ^node)
{
    return node->TreeView == this->_treeView && node->Parent != nullptr && node->Parent->Parent == nullptr;
}

String ^SPlayer::MusicTreeViewManager::listNameFromNode(Node ^anyNode)
{
    System::Diagnostics::Debug::Assert(isListNode(anyNode) || isMusicNode(anyNode));
    if (isListNode(anyNode))
        return anyNode->Text;
    else /*if (isMusicNode(anyNode))*/
        return anyNode->Parent->Text;
}

Music::MusicInfo ^SPlayer::MusicTreeViewManager::musicInfoFromNode(Node ^musicNode)
{
    System::Diagnostics::Debug::Assert(isMusicNode(musicNode));
    if (! isMusicNode(musicNode))
        return nullptr;
    else
        return dynamic_cast<Music::MusicInfo ^>(musicNode->Tag);
}